import pygame
import sys
import os
import random
from utils.config import (
    SCREEN_WIDTH, SCREEN_HEIGHT, GAME_SPEED, BG_IMAGE,
    SNAKE_COLOR, FOOD_COLOR, BACKGROUND_COLOR, FONT_NAME
)
from interfaces.end import EndInterface
from interfaces.leaderboard import update_leaderboard
from interfaces.leaderboard import read_leaderboard 

class GameInterface:
    CELL_SIZE = 20
    BOARD_WIDTH = 40
    BOARD_HEIGHT = 30
    MAP_MARGIN = 0  

    def __init__(self, bg_image_filename="playing_board.jpg", position=None, size=None):
        pygame.init()
        self.width = self.BOARD_WIDTH * self.CELL_SIZE
        self.height = self.BOARD_HEIGHT * self.CELL_SIZE
        if position:
            os.environ['SDL_VIDEO_WINDOW_POS'] = f"{position[0]},{position[1]}"
        self.screen = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption("Snake Game - Main")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.SysFont(FONT_NAME, 32)
        self.bg_image = None
        if bg_image_filename:
            assets_path = os.path.join(os.path.dirname(__file__), '..', 'assets')
            image_path = os.path.join(assets_path, bg_image_filename)
            if os.path.exists(image_path):
                self.bg_image = pygame.image.load(image_path)
                self.bg_image = pygame.transform.scale(self.bg_image, (self.width, self.height))
        self.reset_game()

    def get_playable_area(self):
        """Return the min/max x/y for the playable area (excluding the 2-cell border)."""
        border = 2
        return {
            'min_x': border,
            'max_x': self.BOARD_WIDTH - border - 1,
            'min_y': border,
            'max_y': self.BOARD_HEIGHT - border - 1
        }

    def createMap(self):
        # Draw background image or fill black
        if self.bg_image:
            self.screen.blit(self.bg_image, (0, 0))
        else:
            self.screen.fill((0, 0, 0))

        border_color = (0, 0, 0)
        thickness = 2 * self.CELL_SIZE

        # Top border
        pygame.draw.rect(self.screen, border_color, (0, 0, self.width, thickness))
        # Bottom border
        pygame.draw.rect(self.screen, border_color, (0, self.height - thickness, self.width, thickness))
        # Left border
        pygame.draw.rect(self.screen, border_color, (0, 0, thickness, self.height))
        # Right border
        pygame.draw.rect(self.screen, border_color, (self.width - thickness, 0, thickness, self.height))

    def draw_snake(self):
        for i, (x, y) in enumerate(self.snake):
            color = (255, 255, 0) if i == 0 else SNAKE_COLOR
            rect = pygame.Rect(
                x * self.CELL_SIZE,
                y * self.CELL_SIZE,
                self.CELL_SIZE, self.CELL_SIZE
            )
            pygame.draw.rect(self.screen, color, rect)

    def create_food(self):
        """Generate food only in valid playable area (never in the 2-cell border, never on the snake)."""
        area = self.get_playable_area()
        valid_positions = [
            (x, y)
            for x in range(area['min_x'], area['max_x'] + 1)
            for y in range(area['min_y'], area['max_y'] + 1)
            if (x, y) not in self.snake
        ]
        if not valid_positions:
            return None  # complete victory
        return random.choice(valid_positions)

    def draw_food(self):
        rect = pygame.Rect(
            self.food[0] * self.CELL_SIZE,
            self.food[1] * self.CELL_SIZE,
            self.CELL_SIZE, self.CELL_SIZE
        )
        pygame.draw.rect(self.screen, FOOD_COLOR, rect)

    def draw_score_and_tips(self):
        score_text = self.font.render(f"Score: {self.score}  High Score: {self.high_score}", True, (255, 255, 255))
        self.screen.blit(score_text, (10, 5))
        tip_text = self.font.render("F1: Speed Up  F2: Slow Down  ESC: Quit", True, (200, 200, 200))
        self.screen.blit(tip_text, (8, self.height - 35))

    def biteself(self):
        return self.snake[0] in self.snake[1:]

    def cantcrosswall(self):
        # Check if snake's head is in or touching the border
        x, y = self.snake[0]
        border = 2
        
        # Calculate playable area boundaries
        min_x = border
        max_x = self.BOARD_WIDTH - border - 1
        min_y = border
        max_y = self.BOARD_HEIGHT - border - 1
        
        return (
            x < min_x or 
            x > max_x or 
            y < min_y or 
            y > max_y
        )

    def speedup(self):
        if self.sleeptime > 10:
            self.sleeptime -= 10

    def speeddown(self):
        self.sleeptime += 30

    def snakemove(self):
        if self.next_direction == 'UP' and self.direction != 'DOWN':
            self.direction = 'UP'
        elif self.next_direction == 'DOWN' and self.direction != 'UP':
            self.direction = 'DOWN'
        elif self.next_direction == 'LEFT' and self.direction != 'RIGHT':
            self.direction = 'LEFT'
        elif self.next_direction == 'RIGHT' and self.direction != 'LEFT':
            self.direction = 'RIGHT'

        x, y = self.snake[0]
        if self.direction == 'UP':
            y -= 1
        elif self.direction == 'DOWN':
            y += 1
        elif self.direction == 'LEFT':
            x -= 1
        elif self.direction == 'RIGHT':
            x += 1
        new_head = (x, y)
        self.snake = [new_head] + self.snake[:-1]

    def grow_snake(self):
        self.snake.append(self.snake[-1])

    def handle_input(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    self.next_direction = 'UP'
                elif event.key == pygame.K_DOWN:
                    self.next_direction = 'DOWN'
                elif event.key == pygame.K_LEFT:
                    self.next_direction = 'LEFT'
                elif event.key == pygame.K_RIGHT:
                    self.next_direction = 'RIGHT'
                elif event.key == pygame.K_F1:
                    self.speedup()
                elif event.key == pygame.K_F2:
                    self.speeddown()
                elif event.key == pygame.K_ESCAPE:
                    self.game_over = True

    def is_collision(self):
        """Check for any collision (wall or self)"""
        x, y = self.snake[0]  # Head position
        area = self.get_playable_area()
        # Wall collision: head is outside playable area
        wall_collision = (
            x < area['min_x'] or x > area['max_x'] or
            y < area['min_y'] or y > area['max_y']
        )
        # Self collision
        self_collision = self.snake[0] in self.snake[1:]
        return wall_collision or self_collision

    def update_game_state(self):
        self.snakemove()
        
        # Check collisions first
        if self.is_collision():
            self.game_over = True
            return

        # Handle food eating
        if self.snake[0] == self.food:
            self.grow_snake()
            # Score depends on speed
            if self.sleeptime <= 20:
                self.score += 2
            elif self.sleeptime <= 60:
                self.score += 1
            else:
                self.score += 1
            # Slightly increase speed every time food is eaten
            if self.sleeptime > 10:
                self.sleeptime -= 2  # Decrease delay, so speed increases
            if self.score > self.high_score:
                self.high_score = self.score
                self.write_high_score()
            self.food = self.create_food()

    def write_high_score(self):
        update_leaderboard(self.high_score)

    def reset_game(self):
        # Start snake in the center of the playable area
        area = self.get_playable_area()
        start_x = (area['min_x'] + area['max_x']) // 2
        start_y = (area['min_y'] + area['max_y']) // 2
        self.snake = [(start_x, start_y), (start_x-1, start_y), (start_x-2, start_y)]
        self.direction = 'RIGHT'
        self.next_direction = 'RIGHT'
        self.score = 0
        scores = read_leaderboard()
        self.high_score = scores[0] if scores else 0
        self.game_over = False
        self.speed = GAME_SPEED
        self.sleeptime = 1000 // self.speed
        self.food = self.create_food()

    def start_game(self):
        self.reset_game()
        while True:
            while not self.game_over:
                if self.bg_image:
                    self.screen.blit(self.bg_image, (0, 0))
                else:
                    self.screen.fill(BACKGROUND_COLOR)
                self.createMap()
                self.handle_input()
                self.update_game_state()
                self.draw_snake()
                self.draw_food()
                self.draw_score_and_tips()
                pygame.display.flip()
                self.clock.tick(1000 // self.sleeptime)
            update_leaderboard(self.score)
            end_interface = EndInterface(
                self.screen, self.width, self.height, self.score, self.high_score
            )
            choice = end_interface.show()
            if choice == "replay":
                self.reset_game()
                self.game_over = False
            else:
                break

